type a = {"x": int}
type u = {...a, "u": int}
type v = {"v": int, ...a}
type w = {"j": int, ...a, "k": int, ...v}


type t = {...a, "u": int} as 'a 
type t = {...a, "u": int} => unit
type t = {...a, "u": int} as 'a => unit
type t = ({...a, "u": int}, {...a, "v": int}) => unit

type user = {"name": string} 

let steve: {...user, "age": int} = {"name": "Steve", "age": 30}
let steve = ({"name": "Steve", "age": 30}: {...user, "age": int})
let steve = {({"name": "Steve", "age": 30}: {...user, "age": int})}

let printFullUser = (steve: {...user, "age": int}) => Js.log(steve)
let printFullUser = (~user: {...user, "age": int}) => Js.log(steve)
let printFullUser = (~user: {...user, "age": int}) => Js.log(steve)
let printFullUser = (~user = steve : {...user, "age": int}) => Js.log(steve)

@val
external steve: {...user, "age": int} = "steve"

let makeCeoOf30yearsOld = (name) : {...user, "age": int} => {"name": name, "age": 30}

type optionalUser = option<{...user, "age": int}>
type optionalTupleUser = option<({...user, "age": int}, {...user, "age": int})>
type constrUser = myTypeConstructor<{...user, "age": int}, {...user, "age": int}>

type taggedUser =
  | User({...user, "age": int})
  | Ceo({...user, "age": int, "direction": bool}, {...salary, "taxFraud": bool}) 

type polyTaggedUser = [ #User({...user, "age": int}) ]
type polyTaggedUser2 = [ 
  | #User({...user, "age": int}) 
  | #Ceo({...user, "age": int, "direction": bool}, {...salary, "taxFraud": bool}) 
]

// notice .. and ..., they should have a space
type u<'a> = {.. ...hi} as 'a
type u<'a> = {.. ...hi, "superLongFieldName": string, "superLongFieldName22222222222": int} as 'a
type u<'a> = {.. ...hi, "superLongFieldName": string, ...hi, "superLongFieldName22222222222": int, ...hi} as 'a
